package com.bdqn.mapper;

import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.core.toolkit.StringUtils;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.bdqn.base.Q;
import com.bdqn.util.StringUtil;
import org.apache.ibatis.annotations.Param;

import java.lang.reflect.Method;
import java.util.List;


/**
 * Mapper层的父类接口，实现了基本的CRUD的封装
 *
 * @param <T> 数据对象实体
 * @author LILIBO
 * @since 2021-06-24
 */
public interface IMapper<T> extends BaseMapper<T> {

    /**
     * 方法前缀（通过反射调用getXxx()方法）
     */
    String METHOD_GET = "get";

    /**
     * 排除方法（反射时排除getClass()方法）
     */
    String GET_CLASS = "getClass";

    /**
     * 查询所有数据
     *
     * @return 所有数据
     */
    default List<T> selectAll() {
        return selectList(new QueryWrapper<>());
    }

    /**
     * 根据对象特征查询匹配的对象列表
     *
     * @param param 数据特征
     * @return 符合对象查询条件的对象数据
     */
    default List<T> selectList(T param) {
        QueryWrapper<T> qw = new QueryWrapper<>();
        if (param == null) {
            return selectList(qw);
        }
        // 获得参数类型Class
        Class<?> paramClass = param.getClass();
        // 遍历所有get方法
        for (Method method : paramClass.getMethods()) {
            if (method.getName().startsWith(METHOD_GET) && !method.getName().equals(GET_CLASS) && method.getParameterTypes().length == 0) {
                try {
                    Object value = method.invoke(param);
                    // 判断值是否为默认值（如null、0、""等）
                    if (!StringUtil.isDefaultValue(value)) {
                        // 转换方法名为字段名（如 getUserName -> userName）
                        String fieldName = method.getName().substring(3);
                        fieldName = StringUtils.firstToLowerCase(fieldName);
                        // 动态添加查询条件，并将属性字符串驼峰转下划线格式，如：qw.eq("user_name", value)
                        qw.eq(StringUtils.isNotBlank(fieldName), StringUtils.camelToUnderline(fieldName), value);
                    }
                } catch (Exception e) {
                    e.fillInStackTrace();
                }
            }
        }
        return selectList(qw);
    }

    /**
     * 根据对象特征分页查询匹配的对象列表
     *
     * @param page 分页对象
     * @param param 数据特征
     * @return 符合对象查询条件的对象数据
     */
    default IPage<T> selectPage(Page<T> page, T param) {
        QueryWrapper<T> qw = new QueryWrapper<>();
        if (param == null) {
            return selectPage(page, qw);
        }
        // 获得参数类型Class
        Class<?> paramClass = param.getClass();
        // 遍历所有get方法
        for (Method method : paramClass.getMethods()) {
            if (method.getName().startsWith(METHOD_GET) && !method.getName().equals(GET_CLASS) && method.getParameterTypes().length == 0) {
                try {
                    Object value = method.invoke(param);
                    // 判断值是否为默认值（如null、0、""等）
                    if (!StringUtil.isDefaultValue(value)) {
                        // 转换方法名为字段名（如 getUserName -> userName）
                        String fieldName = method.getName().substring(3);
                        fieldName = StringUtils.firstToLowerCase(fieldName);
                        // 动态添加查询条件，并将属性字符串驼峰转下划线格式，如：qw.eq("user_name", value)
                        qw.eq(StringUtils.isNotBlank(fieldName), StringUtils.camelToUnderline(fieldName), value);
                    }
                } catch (Exception e) {
                    e.fillInStackTrace();
                }
            }
        }
        return selectPage(page, qw);
    }

    /**
     * 根据通用查询对象获取分页数据
     *
     * @param page 分页对象
     * @param query 通用查询对象
     * @return 包含一页数据的分页对象
     */
    default IPage<T> queryPage(Page<T> page, @Param("q") Q query) {
        // 因为无法将通用查询对象中的属性与表中字段关联，默认实现中忽略query参数（实际使用中重写Mapper映射文件）
        QueryWrapper<T> qw = new QueryWrapper<>();
        return selectPage(page, qw);

        /*
        [SysUserMapper.xml]参考示例：
        <select id="queryPage" resultType="sysUser">
            SELECT
            `id`,
            `name`,
            `password`,
            `role_id`,
            `remark`,
            `status`,
            `create_time`,
            `modify_time`
            FROM `sys_user`
            <where>
                <if test="q.name != null and q.name != ''">
                    AND `name` = #{q.name}
                </if>
                <if test="q.keyword != null and q.keyword != ''">
                    AND `name` LIKE CONCAT('%',#{q.keyword},'%')
                </if>
                <if test="q.status != null">
                    AND `status` = #{q.status}
                </if>
                <if test="q.beginDate != null and q.beginDate != ''">
                    AND `create_time` &gt;= #{q.beginDate}
                </if>
                <if test="q.endDate != null and q.endDate != ''">
                    AND `create_time` &lt;= #{q.endDate}
                </if>
                <if test="q.attr.parentId != null">
                    AND `parent_id` = #{q.attr.parentId}
                </if>
            </where>
        </select>
        */
    }

}
